package org.jdesktop.wonderland.modules.kinectcontrol.client;

import java.awt.AWTException;
import java.awt.Canvas;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import kinect.Kinect;
import kinect.skeleton.Skeleton;
import kinect.visual.Imager;
import org.jdesktop.wonderland.client.hud.HUD;
import org.jdesktop.wonderland.client.hud.HUDComponent;
import org.jdesktop.wonderland.client.jme.JmeClientMain;
import org.jdesktop.wonderland.client.login.ServerSessionManager;

/**
 *
 * @author Dominik
 */
public class KinectControlJPanel extends JPanel{

    private HUDComponent kinectHUD;
    private HUD mainHUD;
    private KinectControlJPanel myself;
    private boolean connected = false;
    private HandleKinectFrames frameHandler;
    private Thread thread;
    private SkeletonDataProcessor dataProcessor;
    private Image frame;
    private KeyInputHandler keyListener;
    private static final Logger LOGGER =
            Logger.getLogger(JmeClientMain.class.getName());
    
    static BufferedImage img_video = Imager.getNewVideoImage();
    static BufferedImage img_depth = Imager.getNewDepthGreyscale();
    static BufferedImage img_player = Imager.getNewDepthGreyscale();
    
    /**
     * Creates new form KinectControlJPanel
     */
    public KinectControlJPanel(ServerSessionManager serverSession) {
        initComponents();

        dataProcessor = null;
        boolean failed = false;
        
        myself = this;
        try{
            dataProcessor = new SkeletonDataProcessor("modules/installed/kinect-control/client/gestures.txt", true, serverSession);
        }
        catch(Exception ex)
        {
            failed = true;
            ex.printStackTrace();
            LOGGER.log(Level.WARNING, "Failed loading gesture file: resources/gesturesBDA.txt");
        }
        
        if(failed)
        {
            try{
                dataProcessor = null;
                dataProcessor = new SkeletonDataProcessor("C:\\Users\\Dominik\\Desktop\\gesturesBDA.txt", false, serverSession);
            }
            catch(Exception ex)
            {
                failed = true;
                LOGGER.log(Level.WARNING, "Failed loading gesture file: C:\\Users\\Dominik\\Desktop\\gesturesBDA.txt");
            }
        }
        
        //For KeyMapping, add Keylistern with output
        keyListener = new KeyInputHandler();
        JmeClientMain.getFrame().getCanvas().addKeyListener(keyListener);
        JmeClientMain.getFrame().getCanvas3DPanel().addKeyListener(keyListener);
        JmeClientMain.getFrame().getFrame().addKeyListener(keyListener);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jFileChooser1 = new javax.swing.JFileChooser();
        buttonStart = new javax.swing.JButton();
        buttonStop = new javax.swing.JButton();
        imageLabel = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        angleSlider = new javax.swing.JSlider();
        jLabel2 = new javax.swing.JLabel();
        lableSkel = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        txtKeyInputCode = new javax.swing.JTextField();

        buttonStart.setText("Start Kinect");
        buttonStart.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                buttonStartMouseClicked(evt);
            }
        });

        buttonStop.setText("Stop Kinect");
        buttonStop.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                buttonStopMouseClicked(evt);
            }
        });

        imageLabel.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N

        jLabel1.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        jLabel1.setText("Kinect Camera Angle");

        angleSlider.setMaximum(40);
        angleSlider.setMinimum(-40);
        angleSlider.setMinorTickSpacing(5);
        angleSlider.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                angleSliderStateChanged(evt);
            }
        });

        jLabel2.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        jLabel2.setText("Skeleton Number:");

        lableSkel.setFont(new java.awt.Font("Tahoma", 0, 36)); // NOI18N
        lableSkel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lableSkel.setText("0");

        jLabel3.setText("KeyInput Code");

        txtKeyInputCode.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        txtKeyInputCode.setText("000");
        txtKeyInputCode.setEnabled(false);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(2, 2, 2)
                .addComponent(imageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 402, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(lableSkel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addContainerGap())))
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(10, 10, 10)
                        .addComponent(jLabel3)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(txtKeyInputCode, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(buttonStart)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(buttonStop)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(angleSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(lableSkel))
                    .addComponent(imageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(buttonStart)
                        .addComponent(buttonStop)
                        .addComponent(jLabel1))
                    .addComponent(angleSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(txtKeyInputCode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(5, 5, 5))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void buttonStartMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonStartMouseClicked
        
        try{
            connected = Kinect.start();
           
            if (!connected) {
                LOGGER.log(Level.INFO, "Error in connection.");
            } else {
                connected = true;
                //Kinect.setSensorAngle(20);
                imageLabel.setText("Connection works");
                frameHandler = new HandleKinectFrames(this);
                thread = new Thread(frameHandler);
                thread.start();

                angleSlider.setValue(Kinect.getSensorAngle());
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }

    }//GEN-LAST:event_buttonStartMouseClicked

    private void buttonStopMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonStopMouseClicked
        if (connected) {
            if (frameHandler.isRunning()) {
                frameHandler.setRunning(false);
            }

            Kinect.stop();
            connected = false;
            imageLabel.setText("Connection closed");
        }
    }//GEN-LAST:event_buttonStopMouseClicked

    private void angleSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_angleSliderStateChanged
        if (connected && !angleSlider.getValueIsAdjusting())
        {
            Kinect.setSensorAngle(angleSlider.getValue());
        }
    }//GEN-LAST:event_angleSliderStateChanged
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JSlider angleSlider;
    private javax.swing.JButton buttonStart;
    private javax.swing.JButton buttonStop;
    public javax.swing.JLabel imageLabel;
    private javax.swing.JFileChooser jFileChooser1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel lableSkel;
    private javax.swing.JTextField txtKeyInputCode;
    // End of variables declaration//GEN-END:variables
    
    /**
     *
     * @author Dominik
     */
    public class HandleKinectFrames implements Runnable, ActionListener {

        private KinectControlJPanel panelHUD;
        private boolean running;
        

        public HandleKinectFrames(KinectControlJPanel hud) {
            panelHUD = hud;
            running = true;
            LOGGER.log(Level.INFO, "Thread is started!");
        }

        public void run() {
            
            int counter = 0;
            
            while (running) {
                try {
                    int event_id = Kinect.getNextEvent();
                    switch(event_id)
                    {
                        case 1:
                            //imageLabel.setIcon(new ImageIcon(img_video));
                            //imageLabel.repaint();
                            //myself.repaint();
                            break;
                        case 2:
                            //System.out.println("Depth Buffer updated");
                            break;
                        case 3:
                            int id = Skeleton.getTrackedSkeletonId();
                            panelHUD.lableSkel.setText("" + id);
                            if (Skeleton.isTrackingSomeSkeleton())
                            {
                                dataProcessor.processData(id);
                            }
                            break;
                        case 0:
                            LOGGER.log(Level.INFO, "Kinect shutdown event received - stopping");
                            running = false;
                            break;
                        case 258: /* sporadically get this - ignore it */
                            break;
                        default:
                            LOGGER.log(Level.WARNING, "Unknown Kinect event returned: " + event_id);
                    }
                    //Thread.sleep(100);
                } catch (Exception ex) {
                    LOGGER.log(Level.WARNING, "Error: " + ex.getMessage());
                }
            }

        }
        
        /**
         * @return the running
         */
        public boolean isRunning() {
            return running;
        }

        /**
         * @param running the running to set
         */
        public void setRunning(boolean running) {
            this.running = running;
        }

        public void actionPerformed(ActionEvent e) {
            imageLabel.setText(e.getActionCommand());
        }
    }
    
    public class KeyInputHandler extends KeyAdapter
    {
        @Override
        public void keyPressed(KeyEvent e) {
            txtKeyInputCode.setText("" + e.getKeyCode());
        }       
    }
}
